﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SchoolManagerMVC.Web.Areas.Students.Controllers;
using SchoolManagerMVC.BusinessAbstract.Interfaces;
using System.Web.Mvc;
using SchoolManagerMVC.Tests.Helpers;
using SchoolManagerMVC.Web.Areas.Students.ViewModels;
using SchoolManagerMVC.Repository.EntityFramework;
using SchoolManagerMVC.Web.Models;
using System.Web.Security;

namespace SchoolManagerMVC.Tests.Controllers.StudentArea
{
    //student
    [TestClass]
    public class HomeControllerTests
    {

        Mock<IRepository> _repoMock;
        Mock<IMembership> _repoMembership;

        HomeController controller;
        StudentCreationViewModel studentVM;
        Student student;

        [TestInitialize]
        public void setup()
        {
            _repoMock = new Mock<IRepository>();
            _repoMembership = new Mock<IMembership>();
            controller = new HomeController(_repoMock.Object, _repoMembership.Object);

            student = new Student()
                {
                    FirstName = "Bob",
                    LastName = "Knight",
                    Age = 33,
                    TuitionOwed = 0,
                    UniqueID = Guid.NewGuid()
                };

            studentVM = new StudentCreationViewModel()
            {
                student = student,
                registerModel = new RegisterModel()
                {
                    UserName ="BOB",
                    Password ="Password",
                    ConfirmPassword = "Password",
                    Email = "bob@test.com"
                }
            };

            _repoMock.Setup(x => x.GetSingle<Student>(It.IsAny<Func<Student, bool>>())).Returns(student);
            _repoMembership.Setup(x => x.createUser(studentVM.registerModel.UserName, studentVM.registerModel.Password, studentVM.registerModel.Email)).Returns(MembershipCreateStatus.Success);
            _repoMembership.Setup(x => x.getUserID(studentVM.registerModel.UserName)).Returns(studentVM.student.UniqueID);
            _repoMembership.Setup(x => x.addUserToRole(studentVM.registerModel.UserName, ""));
        }

        [TestMethod]
        public void UnAuthorizedUser_GoesTo_Default()
        {
            var principal = new MockPrincipal(new MockIdentity(""), new string[] {});
            controller.SetFakeControllerContext(principal);
            var result = controller.Index() as RedirectToRouteResult;
            Assert.AreEqual("Default", result.RouteName, "Route name should have been {0}", "Default");
        }

        [TestMethod]
        public void Authorized_User_NotIn_Role_GoesTo_Default()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] {"BadRole"});
            controller.SetFakeControllerContext(principal);
            var result = controller.Index() as RedirectToRouteResult;
            Assert.AreEqual("Default", result.RouteName, "Route name should have been {0}", "Default");
        }

        [TestMethod]
        public void Authorized_User_InRole_GoesTo_Index()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] {"Admin"});
            controller.SetFakeControllerContext(principal);
            var result = controller.Index() as ViewResult;
            Assert.AreEqual("Index", result.ViewName, "Route name should have been {0}", "Index");
        }

        [TestMethod]
        public void Admin_Can_View_Create()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "Admin" });
            controller.SetFakeControllerContext(principal);
            var result = controller.Create() as ViewResult;
            Assert.AreEqual("Create", result.ViewName);
        }

        [TestMethod]
        public void NotAdmin_CreateGet_RedirectsTo_Default()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "BadRole" });
            controller.SetFakeControllerContext(principal);
            var result = controller.Create() as RedirectToRouteResult;
            Assert.AreEqual("Default", result.RouteName, "Route name should have been {0}", "Default");
        }

        [TestMethod]
        public void NotAdmin_CreatePost_RedirectsTo_Default()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "BadRole" });
            controller.SetFakeControllerContext(principal);
            var result = controller.Create(studentVM) as RedirectToRouteResult;
            Assert.AreEqual("Default", result.RouteName, "Route name should have been {0}", "Default");
        }

        [TestMethod]
        public void Admin_RedirectsTo_Student_Default()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "Admin" });
            controller.SetFakeControllerContext(principal);
            var result = controller.Create(studentVM) as RedirectToRouteResult;
            Assert.AreEqual("Student_Default", result.RouteName, "Route name should have been {0}", "Student_Default");
        }

        [TestMethod]
        public void Details_GoTo_Details_View()
        {
            var result = controller.Details(student.UniqueID) as ViewResult;
            Assert.AreEqual("Details", result.ViewName);
            Assert.AreEqual(student, result.Model);
        }

        [TestMethod]
        public void NotAdmin_DeleteGet_RedirectsTo_Default()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "BadRole" });
            controller.SetFakeControllerContext(principal);
            var result = controller.Delete(student.UniqueID) as RedirectToRouteResult;
            Assert.AreEqual("Default", result.RouteName, "Route name should have been {0}", "Default");
        }

        [TestMethod]
        public void NotAdmin_DeletePost_RedirectsTo_Default()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "BadRole" });
            controller.SetFakeControllerContext(principal);
            var result = controller.ConfirmDelete(student) as RedirectToRouteResult;
            Assert.AreEqual("Default", result.RouteName, "Route name should have been {0}", "Default");
        }

        [TestMethod]
        public void NotAdmin_EditGet_RedirectsTo_Default()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "BadRole" });
            controller.SetFakeControllerContext(principal);
            var result = controller.Edit(student.UniqueID) as RedirectToRouteResult;
            Assert.AreEqual("Default", result.RouteName, "Route name should have been {0}", "Default");
        }

        [TestMethod]
        public void NotAdmin_EditPost_RedirectsTo_Default()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "BadRole" });
            controller.SetFakeControllerContext(principal);
            var result = controller.Edit(student) as RedirectToRouteResult;
            Assert.AreEqual("Default", result.RouteName, "Route name should have been {0}", "Default");
        }

        [TestMethod]
        public void Edit_BadModel_GoesTo_Edit()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "Admin" });
            controller.SetFakeControllerContext(principal);
            controller.ModelState.AddModelError("", "Error");
            var result = controller.Edit(student) as ViewResult;
            Assert.AreEqual("Edit", result.ViewName);
            Assert.AreEqual(student, result.Model);
        }

        [TestMethod]
        public void Edit_GoodModel_GoesTo_Details()
        {
            var principal = new MockPrincipal(new MockIdentity("Admin"), new string[] { "Admin" });
            controller.SetFakeControllerContext(principal);
            var result = (RedirectToRouteResult)controller.Edit(student);
            Assert.AreEqual("Details", result.RouteValues["action"]);

        }

        [TestMethod]
        public void Authorization_Attributes_Have_Been_Applied()
        {
            var attributes = typeof(HomeController).GetCustomAttributes(typeof(AuthorizeAttribute), true);

            Assert.IsNotNull(attributes);
            Assert.AreEqual(1, attributes.Length);
            var authAttribute = (AuthorizeAttribute)attributes[0];
            string[] roles = authAttribute.Roles.Split(new char[] { ',' });
            Assert.IsTrue(roles.Contains(Constants.Admin));
            Assert.IsTrue(roles.Contains(Constants.OfficeAdmin));
            Assert.IsTrue(roles.Contains(Constants.Student));
            Assert.IsTrue(roles.Count() == 3);
        }
    }
}
